# =head1 NAME

# gajaxapis-irc-bot - a bot that will support the Google AJAX APIs

# =head1 DESCRIPTION

# The objective is to build an IRC bot that will be able to run limited Javascript and serve as a resource for people searching
# for information on the Google AJAX APIs. This may ultimately include the ability to cross-reference the AJAX APIs Playground
# by Ben Lisbakken and co, documentation for the various APIs, etc. And since it can't be too stuffy, it should include some
# good ol' MSIE bashing.

# =cut



#!/usr/local/bin/perl

use strict;



my $cringer = cringer->new( # Bot initialization routine
 server => 'irc.freenode.net',
 channels => ['#googleajaxapis','#googlemaps','#appengine'],
 nick => 'cringer',
 alt_nicks => ['cringer_','_cringer_','battle_cat','gajaxapis-irc-bot'],
 name => 'cringer, the gajaxapis-irc-bot.',
 dbHost => 'localhost',
 dbName => 'cringer',
 dbUser => 'cringer',
 dbPass => 'cringer'
)->run;






# Define the bot here
package cringer;
use base qw(Bot::BasicBot);
use Chatbot::Eliza;
use DBI;
use LWP::UserAgent;
use JSON;
#use JavaScript;





sub new{ # initialize the bot
 my $class = shift; # get the class 
 my %args = @_;
 my $self = bless Bot::BasicBot->new( %args ); # initialize the underlying bot

 $self->{eliza} = new Chatbot::Eliza; # initialize the eliza response engine

 my ($dbHost,$dbType,$dbName,$dbUser,$dbPass,$d);
 $dbHost = $args{'dbHost'};
 $dbType = gtg($args{'dbType'}) ? $args{'dbType'} : 'mysql';
 $dbName = $args{'dbName'};
 $dbUser = $args{'dbUser'};
 $dbPass = $args{'dbPass'};
 if(gtg($dbHost,$dbType,$dbName,$dbUser,$dbPass)){ # if all database vars are defined, let's connect
  eval { $d = DBI->connect(qq~DBI:$dbType:$dbName:$dbHost~, $dbUser, $dbPass, {PrintError => 0, RaiseError => 0} ); };
  if($@ ne ''){
   warn $@;
   $d = undef;
  }
 }
 $self->{d} = $d;

 # key phrases that I want to respond to :)
 $self->{phrases} = [];
 if(defined($d)){
  $self->{phrases} = $d->selectcol_arrayref(qq~SELECT DISTINCT(phrase) FROM general_responses;~);
 }
 
 $self->{ua} = LWP::UserAgent->new(); # initialize the UserAgent object
 $self->{ua}->default_header('HTTP_REFERER' => 'http://code.google.com/p/gajaxapis-irc-bot');
 
 #warn $self->{phrases};

 #$self->{jsrt} = Javascript::Runtime->new();
 #$self->{jscx} = $self->{jsrt}->create_context();
 #$self->{jscx}->bind_function(write => sub {warn @_;});
 #warn gtg($dbHost,$dbType,$dbName,$dbUser,$dbPass);


 return $self;
}


sub said{
 my $self = shift;
 my $args = shift;
 my $me = $self->{nick};



 # check for key phrases that we want to respond to
 foreach my $phrase (@{$self->{phrases}}){
  my $match=0;
  $match = ($args->{body} =~ /\b$phrase\b/i);
#  eval qq~\$match = (\$args->{body} =\~ /\\b~.$phrase.qq~\\b/i);~;
  if($match){
   $self->say(
    channel => $args->{channel},
    who => $args->{who},
    body => $self->{d}->selectrow_array(qq~SELECT response FROM general_responses WHERE phrase = ? ORDER BY RAND() LIMIT 1;~,{},$phrase)
   );
   last;
  }
 }



# # if someone mentions msie :(
# if($args->{body} =~ /\b(MS)?IE\d*\b/i){

#  my $msg;
#  if(defined($self->{d})){
#   $msg = $self->{d}->selectrow_array(qq~SELECT message FROM msie ORDER BY RAND() LIMIT 1;~);
#  }

#  $self->say(
#   channel => $args->{channel},
#   who => $args->{who},
#   body => gtg($msg) ? $msg : qq~if(navigator.userAgent.indexOf('MSIE')!=-1){window.close()}~
#  );
# }
 

# # if someone mentions flash or flex :(
# if($args->{body} =~ /\b(flash|flex)\b/i){
 
#  my $msg;
#  if(defined($self->{d})){
#   $msg = $self->{d}->selectrow_array(qq~SELECT message FROM flash ORDER BY RAND() LIMIT 1;~);
#  }
  
#  $self->say(
#   channel => $args->{channel},
#   who => $args->{who},
#   body => gtg($msg) ? $msg : qq~Flash and Flex are the spawns of Satan.~
#  );
# }
 
 
 # search query
 if($args->{body} =~ /^(js|web|local|doc|ae|aesample)search: (.*)/i){
  my $searcher = lc($1);
  my $query = my $q = $2;
  
  if($searcher=~/^doc$/i){
   $query .= qq~ site:code.google.com/apis inurl:documentation~;
   $searcher = 'web';
  }elsif($searcher=~/^js$/i){
   $query .= qq~ site:developer.mozilla.org/en/~;
   $searcher = 'web';
  }elsif($searcher=~/^ae$/i){
   $query .= qq~ site:code.google.com/appengine/docs~;
   $searcher = 'web';
  }elsif($searcher=~/^aesample$/i){
   $query .= qq~ site:code.google.com/p/google-app-engine-samples~;
   $searcher = 'web';
  }
  
  $query = urlencode($query);
  my $url = qq~http://ajax.googleapis.com/ajax/services/search/$searcher?v=1.0&q=$query~;
  my $r = $self->{ua}->get($url);
  my $json;
  eval { $json = from_json($r->decoded_content); };
  if($@ ne ''){
   warn $url;
   warn $r->decoded_content;
   warn qq~Error: $@~;
   $self->say(
    channel => $args->{channel},
    who => $args->{who},
    body => qq~I'm sorry, but I encountered an error processing your query.~
   );
  }else{  
   $self->say(
    channel => $args->{channel},
    who => $args->{who},
    body => (($json->{responseData}->{cursor}->{estimatedResultCount}) ? 'Top' : qq~I'm sorry, but there were no~).qq~ search results for "$q":~
   );
  }

  my @results = defined($json->{responseData}->{results}) ? @{$json->{responseData}->{results}} : ();
  my $count=1;
  foreach my $result (@results){
   $self->say(
    channel => $args->{channel},
    who => $args->{who},
    body => qq~$count. ~.$result->{titleNoFormatting}.qq~ ( ~.(($searcher =~ /^web$/)?$result->{unescapedUrl}:qq~$result->{streetAddress} $result->{city}~.((defined($result->{phoneNumbers})) ? qq~ // $result->{phoneNumbers}->[0]->{number}~:'')).qq~ )~
   );
   $count++;
  }
 }elsif($args->{body} =~ /\S+\s+\S+\s+\S+/){ # let's try to translate...
  my $srcLang = $args->{body} =~ s/^([^:]+)(?=->[^:]+:)// ? $1 : ''; # We check for a source language
  my $destLang = $args->{body} =~ s/^->([^:]+):// ? $1 : 'en'; # We check our destination language
  my $url = qq~http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&format=text&langpair=~.urlencode($srcLang).qq~%7c~.urlencode($destLang).qq~&q=~.urlencode($args->{body});
  my $r = $self->{ua}->get($url);
  my $json;
#  warn $url;
#  warn $r->decoded_content;
  eval { $json = from_json($r->decoded_content); };
  if($@ ne ''){
   warn $url;
   warn $r->decoded_content;
   warn qq~Error: $@~;
#   $self->say(
#    channel => $args->{channel},
#    who => $args->{who},
#    body => qq~I'm sorry, but I encountered an error while translating.~
#   );
  }elsif((!defined($json->{responseData}->{error})) && (defined($json->{responseData}->{translatedText})) && ($json->{responseData}->{detectedSourceLanguage} !~ /^(no|$destLang)$/)){  
   $self->say(
    channel => $args->{channel},
    who => $args->{who},
    body => '~'.$args->{who}.qq~ (~.(($srcLang ne '') ? $srcLang : $json->{responseData}->{detectedSourceLanguage}).qq~|~.($destLang).qq~) -> ~.$json->{responseData}->{translatedText}
   );
  }

 }
 
 
 
 if(!$args->{address}){ # If I'm not addressed, just return
  return;
 }

if($args->{body} =~ /^(introduce yourself|about|hello)$/i){ # for an about/hello query
  return qq~Hello, my name is cringer, the gajaxapis-irc-bot. http://code.google.com/p/gajaxapis-irc-bot~;
 }else{ # anything else goes to Eliza
#  $args->{body} =~ /^$self->{nick}:?\b(.$)/i;
#  return $self->{eliza}->transform($1)
  return $self->{eliza}->transform($args->{body})
 }
}


sub help{
 my $self = shift;
 my $args = shift;
 my $me = $self->{nick};
 
 $args->{body} =~ /^help(.*)$/;
 my $query = $1;
 $query =~ s/^\s+//g;
 #warn $query; # debug only
 my(@cols,@w,@o,@vals);
 @cols = ('*');
 if(gtg($query)){
  my $r = qq~MATCH (entry) AGAINST (? IN BOOLEAN MODE)~;
  $cols[@cols] = qq~$r AS rel~; # make the 
  $w[@w] = qq~$r~;
  $o[@o] = qq~$r DESC~;
  push(@vals,$query,$query,$query);
 }
 my $q = $self->{d}->prepare(qq~SELECT ~ . join(',', @cols) . qq~ FROM help~ . (@w > 0 ? qq~ WHERE (~ . join(') AND (', @w) . qq~)~ : '') . (@o > 0 ? qq~ ORDER BY ~ . join(',', @o) : '') . qq~;~);
 $q->execute(@vals) || warn $q->errstr;
 my $c = 0;
 while(my $row = $q->fetchrow_hashref()){
  $self->say(
   channel => $args->{channel},
   who => $args->{who},
   body => $row->{entry}
  );
  $c++;
 }
 if($c == 0){
  return "Sorry; I can't help you with that query.";
 }
}


sub gtg{
 foreach my $v (@_){
  if((!defined($v))||($v!~/\S/)){return 0;}
 }
 return 1;
}


sub urlencode{
 my $str = shift;
 $str =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg;
 return $str;
}


